#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <string.h>

#include <pthread.h>
#include <mqueue.h>
#include <fcntl.h>           /* Pour les constantes O_* */
#include <sys/stat.h>        /* Pour les constantes « mode » */


#include <config.h>
#include <simulation.h>
#include <conditionnement.h>
#include <destockage.h>
#include <impression.h>
#include <palette.h>
#include <stockage.h>
#include <archivage.h>
#include <erreur.h>
#include <ecriture_windows.h>
#include <lecture_windows.h>


int main()
{
	/* Creation et Ouverture journal de log pour le jour */
	/* ----- récuperation de la date du jour */
	time_t temps;
    struct tm * t;
    char date[21];
    temps = time(NULL);
    t = localtime(&temps);
    strftime(date,21,"journal_%d_%m_%y.txt",t);
    
    /* ----- ouverture du fichier */
    FILE *journal = fopen(date,"wa");
    if(journal == NULL)
    {
		printf("Erreur : impossible de créer le journal\n");
		exit(-1);
	}
	
	#ifdef DEBUG
	printf("[MERE] Journal cree\n");
    #endif
    
	/* Creation des mécanismes de communication */
	/* ----- Boites aux lettres */

	mq_unlink(BAL_versErreur);
	mq_unlink(BAL_retErreur);
	mq_unlink(BAL_versArchivage);
	mq_unlink(BAL_versEcriture);
	mq_unlink(BAL_decisionErreur);
	mq_unlink(BAL_versImpression);
	mq_unlink(BAL_versPalette);
	mq_unlink(BAL_versStockage);
	mq_unlink(BAL_versDestockage);
	mq_unlink(BAL_demarrage);

	mqd_t bal[NB_BAL];
	int index=0;
	struct mq_attr param={0,10,sizeof(MSG_versErreur),0};
	bal[index++]=mq_open(BAL_versErreur,O_CREAT,PERMISSION,&param);
	
	param.mq_msgsize=sizeof(MSG_retErreur);
	bal[index++]=mq_open(BAL_retErreur,O_CREAT,PERMISSION,&param);
	
	param.mq_maxmsg=10;
	param.mq_msgsize=sizeof(MSG_versArchivage);
	bal[index++]=mq_open(BAL_versArchivage,O_CREAT,PERMISSION,&param);
	
	param.mq_maxmsg=10;
	param.mq_msgsize=sizeof(MSG_versEcriture);
	bal[index++]=mq_open(BAL_versEcriture,O_CREAT,PERMISSION,&param);
	
	param.mq_maxmsg=1;
	param.mq_msgsize=sizeof(MSG_decisionErreur);
	bal[index++]=mq_open(BAL_decisionErreur,O_CREAT,PERMISSION,&param);
	
	param.mq_maxmsg=1;
	param.mq_msgsize=sizeof(MSG_carton);
	bal[index++]=mq_open(BAL_versImpression,O_CREAT,PERMISSION,&param);
	bal[index++]=mq_open(BAL_versPalette,O_CREAT,PERMISSION,&param);
	bal[index++]=mq_open(BAL_versStockage,O_CREAT,PERMISSION,&param);
	
	param.mq_maxmsg=10;
	param.mq_msgsize=sizeof(MSG_versDestockage);
	bal[index++]=mq_open(BAL_versDestockage,O_CREAT,PERMISSION,&param);
	
	param.mq_maxmsg=1;
	param.mq_msgsize=sizeof(MSG_demarrage);
	bal[index++]=mq_open(BAL_demarrage,O_CREAT,PERMISSION,&param);

	/* ----- mutex */
	pthread_mutex_t mutex_SHM_Stock;
	MutexSHMStock=&mutex_SHM_Stock;
	pthread_mutex_init(MutexSHMStock,NULL);
	
	pthread_mutex_t mutex_SHM_OF;
	MutexSHMOF=&mutex_SHM_OF;
	pthread_mutex_init(MutexSHMOF,NULL);
	
	/* ----- SHM */
	/* ----- zone de stockage */
	SHM_Stockage laZoneDeStockage;
	/* ----- initialisation */
	laZoneDeStockage.nbPaletteA=0;
	laZoneDeStockage.nbPaletteB=0;

	ZoneStockage=&laZoneDeStockage;
	
	/* ----- ordre de fabrication */
	SHM_ParametresOF lOrdreDeFabrication;
	/* ----- initialisation */
	lOrdreDeFabrication.numLot=1;
	lOrdreDeFabrication.nbPaletteA=0;
	lOrdreDeFabrication.taillePaletteA=0;
	lOrdreDeFabrication.tailleCartonA=0;
	lOrdreDeFabrication.nbPaletteB=0;
	lOrdreDeFabrication.taillePaletteB=0;
	lOrdreDeFabrication.tailleCartonB=0;
	
	OrdreFabrication=&lOrdreDeFabrication;


	/* Lancement de la simulation */
	LancerSimu();
	
	#ifdef DEBUG
	printf("[MERE] Ressources creees\n");
	#endif
	
	/* Configuration et lancement des threads */
	/* ----- Création paramètres ordonnancement */
	pthread_attr_t attr;
	struct sched_param schedParam;
	pthread_t threads[NB_THREAD];

	pthread_attr_init(&attr);
	pthread_attr_setschedpolicy(& attr, SCHED_FIFO);
	pthread_attr_setinheritsched(& attr, PTHREAD_EXPLICIT_SCHED);

	/* ----- Configuration thread Mère */
	pthread_setschedprio(pthread_self(),PRIO_MERE);

	/* ----- Lancement des threads */
	/* ----- Ecriture */
	schedParam.sched_priority =PRIO_ECRITURE;
	pthread_attr_setschedparam(& attr, & schedParam);
	pthread_create(&(threads[T_ECRITURE]), &attr,EcritureWindows,NULL);

	/* ----- Archivage */
	schedParam.sched_priority =PRIO_ARCHIVAGE;
	pthread_attr_setschedparam(& attr, & schedParam);
	pthread_create(&(threads[T_ARCHIVAGE]), & attr, Archivage,NULL);

	/* ----- Erreur */
	schedParam.sched_priority =PRIO_ERREUR;
	pthread_attr_setschedparam(& attr, & schedParam);
	pthread_create(&(threads[T_ERREUR]), & attr,Erreur,NULL);	
	
	/* ----- Destockage */
	schedParam.sched_priority =PRIO_DESTOCKAGE;
	pthread_attr_setschedparam(& attr, & schedParam);
	pthread_create(&(threads[T_DESTOCKAGE]), & attr,Destockage,NULL);

	/* ----- Lecture */
	schedParam.sched_priority =PRIO_LECTURE;
	pthread_attr_setschedparam(& attr, & schedParam);
	pthread_create(&(threads[T_LECTURE]), & attr,LectureWindows,NULL);

	/* ----- Stockage */
	schedParam.sched_priority =PRIO_STOCKAGE;
	pthread_attr_setschedparam(& attr, & schedParam);
	pthread_create(&(threads[T_STOCKAGE]), & attr,Stockage,NULL);

	/* ----- Palette */
	schedParam.sched_priority =PRIO_PALETTE;
	pthread_attr_setschedparam(& attr, & schedParam);
	pthread_create(&(threads[T_PALETTE]), & attr,Palette,NULL);

	/* ----- Impression */
	schedParam.sched_priority =PRIO_IMPRESSION;
	pthread_attr_setschedparam(& attr, & schedParam);
	pthread_create(&(threads[T_IMPRESSION]), & attr,Impression,NULL);

	/* ----- Conditionnement */
	schedParam.sched_priority =PRIO_CONDITIONNEMENT;
	pthread_attr_setschedparam(& attr, & schedParam);
	pthread_create(&(threads[T_CONDITIONNEMENT]), & attr,Conditionnement,NULL);

	#ifdef DEBUG
	printf("[MERE] Threads lances\n");
	#endif
	
	/* Fin de l'application */
	/* Synchronisation de fin avec les threads de la chaine de production */
	/* ----- Conditionnement */
	pthread_join(threads[T_CONDITIONNEMENT],NULL);
	#ifdef DEBUG
	printf("[MERE] Conditionnement termine\n");
	#endif
	
	/* ----- Impression */
	pthread_join(threads[T_IMPRESSION],NULL);
	#ifdef DEBUG
	printf("[MERE] Impression termine\n");
	#endif
	
	/* ----- Palette */
	pthread_join(threads[T_PALETTE],NULL);
	#ifdef DEBUG
	printf("[MERE] Palette termine\n");
	#endif
	
	/* ----- Stockage */
	pthread_join(threads[T_STOCKAGE],NULL);
	#ifdef DEBUG
	printf("[MERE] Stockage termine\n");
	#endif
	
	/* ----- Erreur */
	pthread_join(threads[T_ERREUR],NULL);
	#ifdef DEBUG
	printf("[MERE] Erreur termine\n");
	#endif
	
	/* Synchronisation de fin avec les threads de communication */
	/* ----- Lecture */
	pthread_join(threads[T_LECTURE],NULL);
	#ifdef DEBUG
	printf("[MERE] Lecture termine\n");
	#endif
	
	/* ----- Destockage */
	pthread_join(threads[T_DESTOCKAGE],NULL);
	#ifdef DEBUG
	printf("[MERE] Destockage termine\n");
	#endif
	
	/* ----- Archivage */
	pthread_join(threads[T_ARCHIVAGE],NULL);
	#ifdef DEBUG
	printf("[MERE] Archivage termine\n");
	#endif
	
	/* ----- Ecriture */
	pthread_join(threads[T_ECRITURE],NULL);
	#ifdef DEBUG
	printf("[MERE] Ecriture termine\n");
	#endif
	
	/* Arret de la simulation */
	ArreterSimu();
	
	/* Destruction des mécanismes de communication */
	/* ----- mutex */
	pthread_mutex_destroy(MutexSHMStock);
	pthread_mutex_destroy(MutexSHMOF);
	/* ----- BaL */
	index=0;
	mq_close(bal[index++]);
	mq_unlink(BAL_versErreur);
	mq_close(bal[index++]);
	mq_unlink(BAL_retErreur);
	mq_close(bal[index++]);
	mq_unlink(BAL_versArchivage);
	mq_close(bal[index++]);
	mq_unlink(BAL_versEcriture);
	mq_close(bal[index++]);
	mq_unlink(BAL_decisionErreur);
	mq_close(bal[index++]);
	mq_unlink(BAL_versImpression);
	mq_close(bal[index++]);
	mq_unlink(BAL_versPalette);
	mq_close(bal[index++]);
	mq_unlink(BAL_versStockage);
	mq_close(bal[index++]);
	mq_unlink(BAL_versDestockage);
	mq_close(bal[index++]);
	mq_unlink(BAL_demarrage);
	
	/* Fermeture du journal de log */
	fclose(journal);
	
	#ifdef DEBUG
	printf("[MERE] Application terminée\n");
	#endif
	
	/* Fin du processus */
	exit(EXIT_SUCCESS);
}
